﻿// Copyright (C) Jari Hautio <jari.hautio@iki.fi> 2008. Licensed under GPLv2. See LICENSE.txt in solution folder.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace ColorLib
{
    /// <summary>
    /// Class for holding various methods to do color calculations.
    /// </summary>
    public class ColorMath
    {
        public static double[] ToYbCr(Color c1)
        {
            double Y1 =    0 + 0.299    * c1.R + 0.587   * c1.G  + 0.114    * c1.B;
            double cb1 = 128 - 0.168736 * c1.R - 0.331264 * c1.G + 0.5      * c1.B;
            double cr1 = 128 + 0.5      * c1.R - 0.418688 * c1.G - 0.081312 * c1.B;
            return new double[] { Y1, cb1, cr1 };
        }
        public static double[] ToYbCrFast(Color c1)
        {
            double Y1 = 0 + ((77 * c1.R + 150 * c1.G + 29 * c1.B) / 256.0);
            double cb1 = 128 + ((-43 * c1.R - 85 * c1.G + 128 * c1.B) / 256.0);
            double cr1 = 128 + ((128 * c1.R - 107 * c1.G - 21 * c1.B) / 256.0);
            return new double[] { Y1, cb1, cr1 };
        }
        public static double DistanceYCbCr(Color c1, Color c2)
        {
            double Y1 =    0 + 0.299    * c1.R + 0.587   * c1.G  + 0.114    * c1.B;
            double cb1 = 128 - 0.168736 * c1.R - 0.331264 * c1.G + 0.5      * c1.B;
            double cr1 = 128 + 0.5      * c1.R - 0.418688 * c1.G - 0.081312 * c1.B;
            double Y2 =    0 + 0.299    * c2.R + 0.587    * c2.G + 0.114    * c2.B;
            double cb2 = 128 - 0.168736 * c2.R - 0.331264 * c2.G + 0.5      * c2.B;
            double cr2 = 128 + 0.5      * c2.R - 0.418688 * c2.G - 0.081312 * c2.B;
            return
                Math.Pow(Y1 - Y2, 2) + Math.Pow(cb1 - cb2, 2) + Math.Pow(cr1 - cr2, 2);
        }

        public static double DistanceYCbCrFast(Color c1, Color c2)
        {
            double Y1 = 0 + ((77 * c1.R + 150 * c1.G + 29 * c1.B) /256.0);
            double cb1 = 128 + ((-43 * c1.R - 85 * c1.G + 128 * c1.B) /256.0);
            double cr1 = 128 + ((128 * c1.R - 107 * c1.G - 21 * c1.B) /256.0);
            double Y2 = 0 + ((77 * c2.R + 150 * c2.G + 29 * c2.B) /256.0);
            double cb2 = 128 + ((-43 * c2.R - 85 * c2.G + 128 * c2.B) /256.0);
            double cr2 = 128 + ((128 * c2.R - 107 * c2.G - 21 * c2.B) /256.0);
            return
                Math.Pow(Y1 - Y2, 2) + Math.Pow(cb1 - cb2, 2) + Math.Pow(cr1 - cr2, 2);
        }
        public static double DistanceRGBHSV(Color c1, Color c2)
        {
            double d1 = c1.GetHue() - c2.GetHue();
            double d2 = c1.GetHue() > c2.GetHue() ? c1.GetHue() - 360 - c2.GetHue() : c2.GetHue() - 360 - c1.GetHue();
            d1 = Math.Pow(d1, 2);
            d2 = Math.Pow(d2, 2);
            double hsv = 4 * Math.Min(d1, d2) *
                c1.GetSaturation() * c2.GetSaturation() *
                (0.5 - Math.Abs(0.5 - c1.GetBrightness())) *
                (0.5 - Math.Abs(0.5 - c2.GetBrightness()));
            return hsv +
                (Math.Pow((c1.R - c2.R), 2) +
                 Math.Pow((c1.G - c2.G), 2) +
                 Math.Pow((c1.B - c2.B), 2));

        }

        public static double DistanceRGB(Color c1, Color c2)
        {
            return
                Math.Pow((c1.R - c2.R), 2) +
                Math.Pow((c1.G - c2.G), 2) +
                Math.Pow((c1.B - c2.B), 2);
        }
        public static double DistanceUYV(Color c1, Color c2)
        {
            // convert fitst to uyv format
            double Y1 = 0.299 * c1.R + 0.587 * c1.G + 0.114 * c1.B;
            double U1 = 0.492 * (c1.B - Y1);
            double V1 = 0.877 * (c1.R - Y1);
            double Y2 = 0.299 * c2.R + 0.587 * c2.G + 0.114 * c2.B;
            double U2 = 0.492 * (c2.B - Y1);
            double V2 = 0.877 * (c2.R - Y1);
            return
                Math.Pow(Y1 - Y2, 2) + Math.Pow(U1 - U2, 2) + Math.Pow(V1 - V2, 2);
        }
        public static double DistanceHue(Color c1, Color c2)
        {
            double d1 = c1.GetHue() - c2.GetHue();
            double d2 = c1.GetHue() > c2.GetHue() ? c1.GetHue() - 360 - c2.GetHue() : c2.GetHue() - 360 - c1.GetHue();
            d1 = Math.Pow(d1, 2);
            d2 = Math.Pow(d2, 2);
            double hsv = 4 * Math.Min(d1, d2) *
                c1.GetSaturation() * c2.GetSaturation() *
                (0.5 - Math.Abs(0.5 - c1.GetBrightness())) *
                (0.5 - Math.Abs(0.5 - c2.GetBrightness()));
            return hsv;
        }
    }
}
